package com.meiyuetao.myt.partner.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import lab.s2jh.auth.dao.RoleDao;
import lab.s2jh.auth.entity.Role;
import lab.s2jh.auth.entity.User;
import lab.s2jh.auth.service.UserService;
import lab.s2jh.core.dao.BaseDao;
import lab.s2jh.core.service.BaseService;
import lab.s2jh.core.service.Validation;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.hibernate.collection.internal.PersistentBag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.meiyuetao.myt.core.service.SolrService;
import com.meiyuetao.myt.md.dao.BrandDao;
import com.meiyuetao.myt.md.dao.CommodityDao;
import com.meiyuetao.myt.md.entity.Brand;
import com.meiyuetao.myt.md.entity.Commodity;
import com.meiyuetao.myt.partner.dao.PartnerDao;
import com.meiyuetao.myt.partner.dao.PartnerR2BrandDao;
import com.meiyuetao.myt.partner.dao.PartnerR2CommodityDao;
import com.meiyuetao.myt.partner.entity.Partner;
import com.meiyuetao.myt.partner.entity.PartnerR2Brand;
import com.meiyuetao.myt.partner.entity.PartnerR2Commodity;

@Service
@Transactional
public class PartnerService extends BaseService<Partner, Long> {

    @Autowired
    private PartnerDao partnerDao;

    @Autowired
    private UserService userService;

    @Autowired
    private RoleDao roleDao;

    @Autowired
    private PartnerR2CommodityDao partnerR2CommodityDao;

    @Autowired
    private PartnerR2BrandDao partnerR2BrandDao;

    @Autowired
    private CommodityDao commodityDao;

    @Autowired
    private BrandDao brandDao;

    @Autowired
    private SolrService solrService;

    @Override
    protected BaseDao<Partner, Long> getEntityDao() {
        return partnerDao;
    }

    /**
     * 计算当前节点所在层级
     * 
     * @param partner
     * @return
     */
    public int getAgentLevel(Partner partner) {
        int count = 1;
        Partner tmp = partner.getParent();
        if (tmp != null) {
            do {
                count++;
            } while ((tmp = tmp.getParent()) != null);
        }
        return count;
    }

    /**
     * 检查品牌是否关联了代理商（Partner）
     * 
     * @param brand
     * @return 关联了代理商:True | 没关联代理商:False
     */
    public Partner checkBrandHasPartner(Brand brand) {
        List<PartnerR2Brand> brands = partnerR2BrandDao.findByBrand(brand);
        if (CollectionUtils.isNotEmpty(brands)) {
            return brands.get(0).getPartner();
        }
        return null;
    }

    /**
     * 检查商品是否关联了代理商（Partner）
     * 
     * @param brand
     * @return 关联了代理商:True | 没关联代理商:False
     */
    public Partner checkCommodityHasPartner(Commodity commodity) {
        List<PartnerR2Commodity> p2cs = partnerR2CommodityDao.findByCommodity(commodity);
        if (CollectionUtils.isNotEmpty(p2cs)) {
            return p2cs.get(0).getPartner();
        }
        return checkBrandHasPartner(commodity.getBrand());
    }

    /**
     * 检查商品是否属于同一代理商（有父子关系也可）
     * 
     * @param cids
     * @return
     */
    public Boolean checkCommodityAgentPartners(List<Long> cids, Partner partner) {
        if (cids.isEmpty() || cids.size() <= 1)
            return Boolean.TRUE;
        /*
         * ！~ 根据传入的商品ID取出所有对应的代理商（合作伙伴）信息 mergedAgentPartners
         */
        Set<Partner> mergedAgentPartners = new HashSet<Partner>();
        for (Long cid : cids) {
            Commodity commodity = commodityDao.findOne(cid);
            Assert.notNull(commodity);
            boolean flag = Boolean.FALSE;//
            // 1.直接关联的代理商
            List<PartnerR2Commodity> p2cs = partnerR2CommodityDao.findByCommodity(commodity);
            if (CollectionUtils.isNotEmpty(p2cs)) {
                for (PartnerR2Commodity p2c : p2cs) {
                    mergedAgentPartners.add(p2c.getPartner());
                }
            } else {
                flag = Boolean.TRUE;// 商品没有直接关联代理商
            }
            // 2.商品-品牌关联的代理商
            Brand brand = commodity.getBrand();
            if (brand != null) {
                List<PartnerR2Brand> p2bs = partnerR2BrandDao.findByBrand(brand);
                if (CollectionUtils.isNotEmpty(p2bs)) {
                    for (PartnerR2Brand p2b : p2bs) {
                        mergedAgentPartners.add(p2b.getPartner());
                    }
                } else {
                    if (flag) {
                        /*
                         * 商品没有直接关联代理商，并且商品品牌也没有关联代理商才设Null,
                         * 设NULL是为了后续的判断无代理商商品时方便
                         */
                        mergedAgentPartners.add(null);
                    }
                }
            } else {
                if (flag) {
                    // 商品没有直接关联代理商，并且商品也没有关联品牌才设Null,
                    mergedAgentPartners.add(null);
                }
            }
        }
        // 加入销售单选取的代理分销商一同判断
        mergedAgentPartners.add(partner);
        /*
         * ！~ 显而易见的，无需再判断的情况
         */
        if (mergedAgentPartners.contains(null)) {
            return Boolean.FALSE;
        } else if (mergedAgentPartners.size() <= 1) {
            return Boolean.TRUE;
        }

        /*
         * ！~ 检查是否是同一合作伙伴（同一合作伙伴父子路径）
         */

        return checkRelations(mergedAgentPartners);
    }

    /**
     * 检查传入的Partners是否是同一关系树（是：return True；否：return False;）
     * 
     * @param p1
     * @param p2
     * @return
     */
    private Boolean checkRelations(Set<Partner> partners) {
        // 1.同根即同树
        Set<Partner> Roots = Sets.newHashSet();

        for (Partner p : partners) {
            Roots.add(getRoot(p));

        }

        return Roots.size() == 1;
    }

    /**
     * 获取根节点
     * 
     * @param p
     * @return
     */
    public Partner getRoot(Partner p) {
        if (p.getParent() != null) {
            return getRoot(p.getParent());
        } else {
            return p;
        }
    }

    public Iterable<Partner> findAll() {
        return partnerDao.findAll();
    }

    @Override
    public Partner save(Partner entity) {
        if (!entity.isNew()) {
            /*
             * begin:商品/品牌 和 代理商 一对一关系校验
             */
            PersistentBag pb = (PersistentBag) entity.getPartnerR2Brands();
            Object[] objs = pb.toArray();
            if (ArrayUtils.isNotEmpty(objs)) {
                for (Object obj : objs) {
                    PartnerR2Brand p2b = (PartnerR2Brand) obj;
                    Long bid = p2b.getBrand().getId();
                    Brand brand = brandDao.findOne(bid);
                    Partner partner = this.checkBrandHasPartner(brand);
                    if (partner != null && !partner.equals(entity)) {
                        Validation.isTrue(false, "[ " + brand.getDisplay() + " ]已经关联了代理商[ " + partner.getDisplay() + "]，不可重复关联");
                    }
                }
            }

            PersistentBag pb2 = (PersistentBag) entity.getPartnerR2Commodities();
            Object[] objs2 = pb2.toArray();
            if (ArrayUtils.isNotEmpty(objs2)) {
                for (Object obj : objs2) {
                    PartnerR2Commodity p2c = (PartnerR2Commodity) obj;
                    Long cid = p2c.getCommodity().getId();
                    Commodity commodity = commodityDao.findOne(cid);
                    Partner partner = checkCommodityHasPartner(commodity);
                    if (partner != null && !partner.equals(entity)) {
                        Validation.isTrue(false, "[ " + commodity.getTitle() + "[ " + commodity.getDisplay() + " ]已经关联了代理商[ " + partner.getDisplay() + "]，不可重复关联");
                    }
                }
            }
            /*
             * end:商品/品牌 和 代理商 一对一关系校验
             */
        }

        String code = entity.getCode();
        Validation.isTrue(!code.startsWith("ROLE"), "请勿使用'ROLE'作为代码前缀");
        if (entity.isNew()) {
            User user = new User();
            user.setAclCode(entity.getCode());
            user.setEmail(entity.getContactEmail());
            user.setNick(entity.getAbbr());
            user.setSigninid(entity.getExtraAttributesValue("signinid"));
            userService.save(user, entity.getExtraAttributesValue("newpassword"));

            Role role = roleDao.findByCode("ROLE_PARTNER");
            Validation.notNull(role, "未定义ROLE_PARTNER角色");
            userService.updateRelatedRoleR2s(user.getId(), role.getId());
        }

        super.save(entity);
        // 异步更新Solr索引
        solrService.partnerIndexAsync();
        return entity;
    }

    @Transactional(readOnly = true)
    public Partner findByCode(String code) {
        List<Partner> allItems = partnerDao.findAllCached();
        for (Partner item : allItems) {
            if (item.getCode().equals(code)) {
                return item;
            }
        }
        return null;
    }

    @Transactional(readOnly = true)
    public List<Partner> findRoots() {
        List<Partner> roots = Lists.newArrayList();
        List<Partner> allItems = partnerDao.findAllCached();
        for (Partner item : allItems) {
            if (item.getParent() == null) {
                roots.add(item);
            }
        }
        Collections.sort(roots);
        return roots;
    }

    @Transactional(readOnly = true)
    public List<Partner> findChildren(Partner parent) {
        if (parent == null) {
            return findRoots();
        }
        List<Partner> children = new ArrayList<Partner>();
        List<Partner> allItems = partnerDao.findAllCached();
        for (Partner item : allItems) {
            if (parent.equals(item.getParent())) {
                children.add(item);
            }
        }
        Collections.sort(children);
        return children;
    }

    /**
     * 获取合作伙伴所在树的所有节点
     * 
     * @param entity
     *            合作伙伴
     * @return 所有节点集合
     */
    @Transactional(readOnly = true)
    public Set<Partner> getAllNode(Partner entity) {
        Set<Partner> childrenNodes = Sets.newHashSet();
        findAllChildrenNode(this.getRoot(entity), childrenNodes);
        return childrenNodes;
    }

    /**
     * 递归查找节点的所有子节点
     * 
     * @param root
     *            根节点
     * @param childrenNodes
     */
    @Transactional(readOnly = true)
    public void findAllChildrenNode(Partner root, Set<Partner> childrenNodes) {
        childrenNodes.add(root);
        List<Partner> chd = findChildren(root);
        if (CollectionUtils.isNotEmpty(chd)) {
            for (Partner node : chd) {
                findAllChildrenNode(node, childrenNodes);
            }
        }
    }

    /**
     * 获取代理商关联的所有商品（目前：整棵树共享商品关联）
     * 
     * @param entity
     * @return
     */
    @Transactional(readOnly = true)
    public List<Commodity> getRelationedCommodities(Partner entity) {
        Set<Partner> allNode = getAllNode(entity);
        List<Commodity> cs = partnerDao.findRelationedCommodities(allNode);
        return cs;
    }

    /**
     * 获取代理商关联的所有品牌（目前：整棵树共享品牌关联）
     * 
     * @param entity
     * @return
     */
    @Transactional(readOnly = true)
    public List<Brand> getRelationedBrands(Partner entity) {
        Set<Partner> allNode = getAllNode(entity);
        List<Brand> bs = partnerDao.findRelationedBrands(allNode);
        return bs;
    }
}
